package com.yYclass.service.impl;

import com.yYclass.component.SmsComponent;
import com.yYclass.config.RabbitMQConfig;
import com.yYclass.constant.RedisKey;
import com.yYclass.controller.request.AccountLoginRequest;
import com.yYclass.controller.request.AccountRegisterRequest;
import com.yYclass.enums.AuthTypeEnum;
import com.yYclass.enums.BizCodeEnum;
import com.yYclass.enums.EventMessageType;
import com.yYclass.enums.SendCodeEnum;
import com.yYclass.manager.AccountManager;
import com.yYclass.model.AccountDO;
import com.yYclass.mapper.AccountMapper;
import com.yYclass.model.EventMessage;
import com.yYclass.model.LoginUser;
import com.yYclass.service.AccountService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yYclass.service.NotifyService;
import com.yYclass.util.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.Md5Crypt;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 栗永松
 * @since 2024-04-09
 */
@Service
@Slf4j
public class AccountServiceImpl extends ServiceImpl<AccountMapper, AccountDO> implements AccountService {
    /**
     * 10分钟有效
     */
    private static final int CODE_EXPIRED = 60*1000*10;

    @Autowired
    private NotifyService notifyService;

    @Autowired
    private AccountManager accountManager;

    @Autowired
    private SmsComponent smsComponent;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private RabbitMQConfig rabbitMQConfig;
    /**
     * 免费流量包商品id
     */
    private static final Long FREE_TRAFFIC_PRODUCT_ID = 1L;
    @Override
    public JsonData sendCode(SendCodeEnum userRegister, String to) {
        String cacheKey = String.format(RedisKey.CHECK_CODE_KEY,userRegister.name(),to);
        String cacheValue = redisTemplate.opsForValue().get(cacheKey);
        //如果不为空，再判断是否是60秒内重复发送 0122_232131321314132
        if (StringUtils.isNoneBlank(cacheValue)){
            long l = Long.parseLong(cacheValue.split("_")[1]);
            Long left = CommonUtil.getCurrentTimestamp()-l;
            if (left < (60 * 1000)){
                //当前时间戳-验证码发送的时间戳，如果小于60秒，则不给重复发送
                log.info("重复发送短信验证码，时间间隔:{}秒",left);
                return JsonData.buildResult(BizCodeEnum.CODE_LIMITED);
            }
        }

        // 获得随机的6为数字
        String code = CommonUtil.getRandomCode(6);
        //生成拼接好验证码
        String value = code+"_"+CommonUtil.getCurrentTimestamp();
        redisTemplate.opsForValue().set(cacheKey,value,CODE_EXPIRED, TimeUnit.MILLISECONDS);
        if (CheckUtil.isEmail(to)){

        }else if (CheckUtil.isPhone(to)){
            smsComponent.send(to,"","【宥宥课堂】您的验证码如下，请勿泄露："+ code +"。");
        }
        return JsonData.buildSuccess();
    }
    /**
     * 手机验证码验证
     * 密码加密（TODO）
     * 账号唯一性检查(TODO)
     * 插入数据库
     * 新注册用户福利发放(TODO)
     *
     * @param registerRequest
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public JsonData register(AccountRegisterRequest registerRequest) {
        boolean checkCode =false;
        //判断验证码
        if(StringUtils.isNotBlank(registerRequest.getPhone())){
            checkCode = notifyService.checkCode(SendCodeEnum.USER_REGISTER,registerRequest.getPhone(),registerRequest.getCode());

        }
        //验证码错误
        if(!checkCode){
            return JsonData.buildResult(BizCodeEnum.CODE_ERROR);
        }

        AccountDO accountDO = new AccountDO();

        BeanUtils.copyProperties(registerRequest,accountDO);
        //认证级别
        accountDO.setAuth(AuthTypeEnum.DEFAULT.name());

        //生成唯一的账号  TODO
        accountDO.setAccountNo(Long.valueOf(IDUtil.geneSnowFlakeID().toString()));

        //设置密码 秘钥 盐
        accountDO.setSecret("$1$"+CommonUtil.getStringNumRandom(8));
        String cryptPwd = Md5Crypt.md5Crypt(registerRequest.getPwd().getBytes(),accountDO.getSecret());
        accountDO.setPwd(cryptPwd);

        int rows = accountManager.insert(accountDO);
        log.info("rows:{},注册成功:{}",rows,accountDO);

        //用户注册成功，发放福利
        userRegisterInitTask(accountDO);

        return JsonData.buildSuccess();
    }

    @Override
    public JsonData login(AccountLoginRequest request) {
        List<AccountDO> accountDOList = accountManager.findByPhone(request.getPhone());

        if(accountDOList!=null && accountDOList.size() ==1){
            AccountDO accountDO = accountDOList.get(0);
            String md5Crypt = Md5Crypt.md5Crypt(request.getPwd().getBytes(), accountDO.getSecret());
            if(md5Crypt.equalsIgnoreCase(accountDO.getPwd())){
                LoginUser loginUser = LoginUser.builder().build();
                BeanUtils.copyProperties(accountDO,loginUser);
                String token = JWTutil.geneJsonWebTokne(loginUser);
                return JsonData.buildSuccess(token);
            }else {
                return JsonData.buildResult(BizCodeEnum.ACCOUNT_PWD_ERROR);
            }
        }else {
            return JsonData.buildResult(BizCodeEnum.ACCOUNT_UNREGISTER);
        }
    }

    /**
     * 用户初始化，发放福利：流量包
     * @param accountDO
     */
    private void userRegisterInitTask(AccountDO accountDO) {
        EventMessage eventMessage = EventMessage.builder()
                .messageId(IDUtil.geneSnowFlakeID().toString())
                .accountNo(accountDO.getAccountNo())
                .eventMessageType(EventMessageType.TRAFFIC_FREE_INIT.name())
                .bizId(FREE_TRAFFIC_PRODUCT_ID.toString())
                .build();

        //发送发放流量包消息
        rabbitTemplate.convertAndSend(rabbitMQConfig.getTrafficEventExchange(),
                rabbitMQConfig.getTrafficFreeInitRoutingKey(),eventMessage);

    }
}
